/**************************************************************************//**
 * @file     drv_lcd.c
 * @version  V1.00
 * $Revision: 1 $
 * $Date: 16/02/17 2:44p $
 * @brief    NUC970 LCM driver source file
 *
 * @note
 * SPDX-License-Identifier: Apache-2.0
 * @Copyright (C) 2021 THEWON. All rights reserved.
*****************************************************************************/
#include <board.h>

#ifdef BSP_USING_LCD
#include "nuc970.h"
#include "nuc970_lcd.h"
#include "nuc970_mfp.h"
#include "lcd_port.h"
#include "drv_sys.h"
#include "drv_gpio.h"

//#define DRV_DEBUG
#define LOG_TAG              "drv.lcd"
#include <drv_log.h>

UINT8 *u8FrameBufPtr, *u8OSDFrameBufPtr;

static void lcmIntHandler(int vector, void *param)
{
    /* clear VPOST interrupt state */
    UINT32 uintstatus;

    uintstatus = inpw(REG_LCM_INT_CS);
    if (uintstatus & VPOSTB_UNDERRUN_INT)
    {
        outpw(REG_LCM_INT_CS, inpw(REG_LCM_INT_CS) | VPOSTB_UNDERRUN_INT);
        LOG_E("LCD under run error!!");
    }
    else if (uintstatus & VPOSTB_BUS_ERROR_INT)
    {
        outpw(REG_LCM_INT_CS, inpw(REG_LCM_INT_CS) | VPOSTB_BUS_ERROR_INT);
        LOG_E("LCD bus error!!");
    }
}

void turn_off_lcd_backlight(void)
{
    rt_pin_mode(LCD_DISP_GPIO_NUM, PIN_MODE_OUTPUT_PULLUP);

    rt_pin_write(LCD_DISP_GPIO_NUM, PIN_LOW);
}

void turn_on_lcd_backlight(void)
{
    rt_pin_mode(LCD_DISP_GPIO_NUM, PIN_MODE_OUTPUT_PULLUP);

    rt_pin_write(LCD_DISP_GPIO_NUM, PIN_HIGH);
}

int drv_lcd_hw_init(void)
{
    rt_err_t result = RT_EOK;

    MFP_LCMInit();

    rt_pin_mode(LCD_DE_GPIO_NUM, PIN_MODE_OUTPUT_PULLDOWN);
    rt_pin_write(LCD_DE_GPIO_NUM, PIN_LOW);

    // outpw(REG_LCM_DCCS, inpw(REG_LCM_DCCS) & ~(VPOSTB_DISP_OUT_EN | VPOSTB_VA_EN));
    // outpw(REG_LCM_OSD_WINS, 0);
    // outpw(REG_LCM_OSD_WINE, 0);
    // outpw(REG_LCM_OSD_OVERLAY, inpw(REG_LCM_OSD_OVERLAY) & 0xFFFFFFF0);
    // outpw(REG_LCM_DCCS, inpw(REG_LCM_DCCS) & (~VPOSTB_OSD_EN));

    // Init LCD interface for E50A2V1 LCD module
    vpostLCMInit(&VPOST_TYPE);

    // Set scale to 1:1
    vpostVAScalingCtrl(1, 0, 1, 0, VA_SCALE_INTERPOLATION);

    // Set display color depth
    vpostSetVASrc(VASRC_TYPE);

    // Get pointer of video frame buffer
    // Note: before get pointer of frame buffer, must set display color depth first
    u8FrameBufPtr = vpostGetFrameBuffer();
    if(u8FrameBufPtr == NULL)
    {
        MFP_LCMDeInit();
        result = -RT_ERROR;
    }

    rt_hw_interrupt_install(LCD_IRQn, lcmIntHandler, RT_NULL, "lcm");
    rt_hw_interrupt_set_priority(LCD_IRQn, IRQ_LEVEL_2);
    rt_hw_interrupt_umask(LCD_IRQn);

    outpw(REG_LCM_DCCS, inpw(REG_LCM_DCCS) | VPOSTB_DISP_INT_EN);
    outpw(REG_LCM_INT_CS, inpw(REG_LCM_INT_CS) | VPOSTB_UNDERRUN_EN);

    // Start to display
    if((inpw(REG_LCM_DCCS) & VPOSTB_SINGLE) == VPOSTB_SINGLE)
        while((inpw(REG_LCM_DCCS) & VPOSTB_VA_EN) == VPOSTB_VA_EN);//wait VA_EN low
    outpw(REG_LCM_DCCS, inpw(REG_LCM_DCCS) | VPOSTB_DISP_OUT_EN); //display_out-enable
    outpw(REG_LCM_DCCS, inpw(REG_LCM_DCCS) | VPOSTB_VA_EN); //va-enable
while((inpw(REG_LCM_DCCS) & VPOSTB_DISP_ON) != VPOSTB_DISP_ON){;}//wait VA_EN low
    return result;
}
INIT_DEVICE_EXPORT(drv_lcd_hw_init);

#endif /* BSP_USING_LCD */
